#pragma once

#include "fwd.h"
#include "path.h"
#include "dir.h"
#include <string>


namespace evm { namespace fs {

using std::string;

void copy(const string& from, const string& to, copy_options options, error_code& ec);
void copy_symlink(const string& existing_symlink, const string& new_symlink, error_code& ec);
string read_symlink(const string& p, error_code& ec);
void create_symlink(const string& to, const string& new_symlink, error_code& ec);
void copy_symlink(const string& existing_symlink, const string& new_symlink, error_code& ec);
bool create_directories(const string& p_str, error_code& ec) noexcept;
bool create_directory(const string& p, error_code& ec);
bool create_directory(const string& p, const string& attributes, error_code& ec);
void create_hard_link(const string& to, const string& new_hard_link, error_code& ec);
string current_path(error_code& ec);
void current_path(const string& p, error_code& ec);
bool equivalent(const string& p1, const string& p2, error_code& ec);
uintmax_t file_size(const string& p, error_code& ec);
uintmax_t hard_link_count(const string& p, error_code& ec);
bool is_empty(const string& p, error_code& ec);
file_time_type last_write_time(const string& p, error_code& ec);
void last_write_time(const string& p, file_time_type new_time, error_code& ec);
void permissions(const string& p, perms prms, error_code& ec);
bool remove(const string& p, error_code& ec);
uintmax_t remove_all(const string& p, error_code& ec);
void rename(const string& from, const string& to, error_code& ec);
void resize_file(const string& p, uintmax_t size, error_code& ec);
space_info space(const string& p, error_code& ec);
file_status status(const string& p, error_code& ec);
file_status symlink_status(const string& p, error_code& ec);
string system_complete(const string& p, error_code& ec);
string temp_directory_path(error_code& ec);

string absolute(const string& p, const string& base = current_path());

string canonical(const string& p, const string& base = current_path(), bool raise = false);

bool copy(const string& from, const string& to, copy_options options, bool raise = false);

inline bool copy(const string& from, const string& to, bool raise = false) {
    return copy(from, to, copy_options::none, raise);
}

bool copy_file(const string& from, const string& to, copy_options options, bool raise = false);

inline bool copy_file(const string& from, const string& to, bool raise = false) {
    return copy_file(from, to, copy_options::none, raise);
}

bool copy_symlink(const string& existing_symlink, const string& new_symlink, bool raise = false);

string read_symlink(const string& p, bool raise = false);

bool create_symlink(const string& to, const string& new_symlink, bool raise = false);

bool create_directories(const string& p, bool raise = false);

bool create_directory(const string& p, bool raise = false);

bool create_directory(const string& p, const string& attributes, bool raise = false);

bool create_directory_symlink(const string& to, const string& new_symlink, bool raise = false);

bool create_hard_link(const string& to, const string& new_hard_link, bool raise = false);

//string current_path(bool raise = false);

bool current_path(const string& p, bool raise = false);

inline bool exists(file_status s) noexcept { return status_known(s) && s.type() != file_type::not_found; }

inline bool exists(const string& p) { return exists(status(p)); }

inline bool exists(const string& p, error_code& ec) { return exists(status(p, ec)); }

bool equivalent(const string& p1, const string& p2, bool raise = false);

uintmax_t file_size(const string& p, bool raise = false);

uintmax_t hard_link_count(const string& p, bool raise = false);

inline bool is_block_file(file_status s) noexcept { return s.type() == file_type::block; }

inline bool is_block_file(const string& p) { return is_block_file(status(p)); }

inline bool is_character_file(file_status s) noexcept { return s.type() == file_type::character; }

inline bool is_character_file(const string& p) { return is_character_file(status(p)); }

inline bool is_directory(file_status s) noexcept { return s.type() == file_type::directory; }

inline bool is_directory(const string& p) { return is_directory(status(p)); }

inline bool is_directory(const string& p, error_code& ec) { return is_directory(status(p, ec)); }

bool is_empty(const string& p, bool raise = false);

inline bool is_fifo(file_status s) noexcept { return s.type() == file_type::fifo; }

inline bool is_fifo(const string& p) { return is_fifo(status(p)); }

inline bool is_other(file_status s) noexcept {
    return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s);
}

inline bool is_other(const string& p) { return is_other(status(p)); }

inline bool is_regular_file(file_status s) noexcept { return s.type() == file_type::regular; }

inline bool is_regular_file(const string& p) { return is_regular_file(status(p)); }

inline bool is_socket(file_status s) noexcept { return s.type() == file_type::socket; }

inline bool is_socket(const string& p) { return is_socket(status(p)); }

inline bool is_symlink(file_status s) noexcept { return s.type() == file_type::symlink; }

inline bool is_symlink(const string& p) { return is_symlink(symlink_status(p)); }

inline bool is_symlink(const string& p, error_code& ec) { return is_symlink(symlink_status(p, ec)); }

file_time_type last_write_time(const string& p, bool raise = false);

bool last_write_time(const string& p, file_time_type new_time, bool raise = false);

enum Mode { READ, WRITE, EXECUTE };

bool access(const string& p, Mode mode, bool raise = false);

bool permissions(const string& p, perms prms, bool raise = false);

bool remove(const string& p, bool raise = false);

uintmax_t remove_all(const string& p, bool raise = false);

bool rename(const string& from, const string& to, bool raise = false);

bool resize_file(const string& p, uintmax_t size, bool raise = false);

space_info space(const string& p, bool raise = false);

inline bool status_known(file_status s) noexcept { return s.type() != file_type::none; }

file_status status(const string& p, error_code& ec);
//file_status status(const string& p, bool raise = false);

file_status symlink_status(const string& p, error_code& ec);
//file_status symlink_status(const string& p, bool raise = false);

string system_complete(const string& p, bool raise = false);

string temp_directory_path(bool raise = false);

}}
